#include "RCSwitch.h"

#if not defined( RCSwitchDisableReceiving )
/**
 * Enable receiving data
 */
void RCSwitch::enableReceive(int interrupt) {
  this->nReceiverInterrupt = interrupt;
  this->enableReceive();
}

void RCSwitch::enableReceive() {
  if (this->nReceiverInterrupt != -1) {
    RCSwitch::nReceivedCode[0] = 0;
    RCSwitch::nReceivedCodeLen = NULL;
    RCSwitch::bAvailable = false;
    attachInterrupt(this->nReceiverInterrupt, handleInterrupt, CHANGE);
  }
}

/**
 * Set Receiving Tolerance
 */
#if not defined( RCSwitchDisableReceiving )
void RCSwitch::setReceiveTolerance(int nPercent) {
  RCSwitch::nReceiveTolerance = nPercent;
}
#endif

/**
 * Disable receiving data
 */
void RCSwitch::disableReceive() {
  detachInterrupt(this->nReceiverInterrupt);
  this->nReceiverInterrupt = -1;
}

bool RCSwitch::available() {
  return RCSwitch::bAvailable;
}

void RCSwitch::resetAvailable() {
  RCSwitch::bAvailable = false;
}

unsigned int RCSwitch::getReceivedCodeLen() {
  return RCSwitch::nReceivedCodeLen;
}

unsigned int RCSwitch::getReceivedDelay() {
  return RCSwitch::nReceivedDelay;
}

unsigned int RCSwitch::getReceivedProtocol() {
  return RCSwitch::nReceivedProtocol;
}

unsigned int* RCSwitch::getReceivedRawData() {
  return RCSwitch::timings;
}
unsigned int RCSwitch::getReceivedRawDataLen() {
  return RCSwitch::nChangeCount;
}

char* RCSwitch::getReceivedCode() {
  return RCSwitch::nReceivedCode;
}

char* RCSwitch::getReceivedCodeDesc() {
  return RCSwitch::nReceivedCodeDesc;
}

/**
 *
 */
bool RCSwitch::receiveProtocol1(unsigned int changeCount){

  changeCount--; // skip the last pulse: it is sta<rting synch pulse for the subsequent datagram

  if (changeCount != 49) {
    return false;
  }

  unsigned long delay = RCSwitch::timings[0] / 31;
  unsigned long delayTolerance = delay * RCSwitch::nReceiveTolerance * 0.01;    

  char* code = RCSwitch::nReceivedCode;
  int codePos = 0;

  bool hasPrevValue = false;
  bool prevValue = false;
  bool thisValue = false;

  for (int i = 1; i<changeCount ; i=i+2) {

    if (RCSwitch::timings[i] > delay-delayTolerance && 
      RCSwitch::timings[i] < delay+delayTolerance &&
      RCSwitch::timings[i+1] > delay*3-delayTolerance && 
      RCSwitch::timings[i+1] < delay*3+delayTolerance) {

      thisValue = false;
    } 
    else if (RCSwitch::timings[i] > delay*3-delayTolerance && 
      RCSwitch::timings[i] < delay*3+delayTolerance && 
      RCSwitch::timings[i+1] > delay-delayTolerance && 
      RCSwitch::timings[i+1] < delay+delayTolerance) {

      thisValue = true;      
    } 
    else {
      // Failed
      return false;
    }

    if (hasPrevValue) {
      char c = thisValue ? ( prevValue ? '1' : 'F' ) : (prevValue ? 'E' : '0'); //E = error. 1 + 0 not a valid combo
      if (c == 'E') return false;
      code[codePos++] = c;
      hasPrevValue = false;        
    }
    else {
      hasPrevValue = true;
      prevValue = thisValue;
    }
  }    

  if (hasPrevValue) {
    //is this possible? return false instead??
    //    code1[code1Pos++] = prevValue;// half a value is left??'E'; // Error: half a value is left
    return false;
  }

  code[codePos] = 0; //nullterm

  RCSwitch::nReceivedProtocol = 1;
  strcpy(RCSwitch::nReceivedCodeDesc, "Code [01F]: ");
  RCSwitch::nReceivedCodeLen = codePos;
  RCSwitch::nReceivedDelay = delay;

  return true;
}


/**
 * PS: must probe protocl 2 AFTER protocol 1, because protocol 2 is a subset of protocol 1
 */
bool RCSwitch::receiveProtocol2(unsigned int changeCount){

  changeCount--; // skip the last pulse: it is sta<rting synch pulse for the subsequent datagram

  if (changeCount != 49) {
    return false;
  }

  unsigned long delay = RCSwitch::timings[0] / 31;
  unsigned long delayTolerance = delay * RCSwitch::nReceiveTolerance * 0.01;    

  char* code = RCSwitch::nReceivedCode;
  int codePos = 0;

  for (int i = 1; i<changeCount ; i=i+2) {

    if (RCSwitch::timings[i] > delay-delayTolerance && 
      RCSwitch::timings[i] < delay+delayTolerance &&
      RCSwitch::timings[i+1] > delay*3-delayTolerance && 
      RCSwitch::timings[i+1] < delay*3+delayTolerance) {

      code[codePos++] = '0';
    } 
    else if (RCSwitch::timings[i] > delay*3-delayTolerance && 
      RCSwitch::timings[i] < delay*3+delayTolerance && 
      RCSwitch::timings[i+1] > delay-delayTolerance && 
      RCSwitch::timings[i+1] < delay+delayTolerance) {

      code[codePos++] = '1';        
    } 
    else {
      // Failed
      return false;
    }
  }    

  code[codePos] = 0; //nullterm

  RCSwitch::nReceivedProtocol = 2;
  strcpy(RCSwitch::nReceivedCodeDesc, "Code [01]: ");
  RCSwitch::nReceivedCodeLen = codePos;
  RCSwitch::nReceivedDelay = delay;

  return true;
}


bool RCSwitch::receiveProtocol3(unsigned int changeCount){

  changeCount--;

  //TODO: no idea if this is correct. No idea what kind of protocol this is. No idea of anything. rc-switch has not documented this protocol at all.
  if (changeCount != 49) {
    return false;
  }

  unsigned long delay = RCSwitch::timings[0] / 10;
  unsigned long delayTolerance = delay * RCSwitch::nReceiveTolerance * 0.01;    

  char* code = RCSwitch::nReceivedCode;
  int codePos = 0;

  for (int i = 1; i<changeCount ; i=i+2) {

    if (RCSwitch::timings[i] > delay-delayTolerance && 
      RCSwitch::timings[i] < delay+delayTolerance && 
      RCSwitch::timings[i+1] > delay*2-delayTolerance && 
      RCSwitch::timings[i+1] < delay*2+delayTolerance) {

      code[codePos++] = '0';
    } 
    else if (RCSwitch::timings[i] > delay*2-delayTolerance && 
      RCSwitch::timings[i] < delay*2+delayTolerance && 
      RCSwitch::timings[i+1] > delay-delayTolerance && 
      RCSwitch::timings[i+1] < delay+delayTolerance) {

      code[codePos++] = '1';
    } 
    else {
      // Failed
      return false;
    }
  }      

  code[codePos] = 0; //nullterm

  RCSwitch::nReceivedCodeLen = codePos;
  strcpy(RCSwitch::nReceivedCodeDesc, "Code [01]: ");
  RCSwitch::nReceivedDelay = delay;
  RCSwitch::nReceivedProtocol = 3;

  return true;
}

/** Protocol 4 is used by BL35P02. (Well...BL35P02 is a CPU...it make no sense to say that a CPU use protocol X. It's like saying this procol is used by atmega328p)
 *
 */
bool RCSwitch::receiveProtocol4(unsigned int changeCount){

  changeCount--;

  //TODO: no idea if this is correct. No idea what kind of protocol this is. No idea of anything. rc-switch has not documented this protocol.
  if (changeCount != 49) {
    return false;
  }

  unsigned long delay = RCSwitch::timings[0] / PROTOCOL4_SYNC_FACTOR;
  unsigned long delayTolerance = delay * RCSwitch::nReceiveTolerance * 0.01;    

  char* code = RCSwitch::nReceivedCode;
  int codePos = 0;

  for (int i = 1; i<changeCount ; i=i+2) {

    if  (RCSwitch::timings[i]   > delay*PROTOCOL4_0_HIGH_CYCLES - delayTolerance
      && RCSwitch::timings[i]   < delay*PROTOCOL4_0_HIGH_CYCLES + delayTolerance
      && RCSwitch::timings[i+1] > delay*PROTOCOL4_0_LOW_CYCLES  - delayTolerance
      && RCSwitch::timings[i+1] < delay*PROTOCOL4_0_LOW_CYCLES  + delayTolerance) {

      code[codePos++] = '0';
    } 
    else if (RCSwitch::timings[i]   > delay*PROTOCOL4_1_HIGH_CYCLES - delayTolerance
      && RCSwitch::timings[i]   < delay*PROTOCOL4_1_HIGH_CYCLES + delayTolerance
      && RCSwitch::timings[i+1] > delay*PROTOCOL4_1_LOW_CYCLES  - delayTolerance
      && RCSwitch::timings[i+1] < delay*PROTOCOL4_1_LOW_CYCLES  + delayTolerance) {

      code[codePos++] = '1';
    } 
    else {
      // Failed
      return false;
    }
  }      

  code[codePos] = 0; //nullterm

  RCSwitch::nReceivedCodeLen = codePos;
  strcpy(RCSwitch::nReceivedCodeDesc, "Code [01]: ");
  RCSwitch::nReceivedDelay = delay;
  RCSwitch::nReceivedProtocol = 4;

  return true;
}


/** Protocol 5 is used by MC145026.
 *
 */
bool RCSwitch::receiveProtocol5(unsigned int changeCount){

  if (changeCount != 36) {
     return false;
  }

  unsigned long delay = RCSwitch::timings[0] / MC145026_DATAGRAM_SEPARATOR_CYCLES; // datagram separator
  unsigned long delayTolerance = delay * RCSwitch::nReceiveTolerance * 0.01;    

  char* code = RCSwitch::nReceivedCode;
  int codePos = 0;

  bool hasPrevValue = false;  
  bool prevValue = false;  
  bool thisValue = false;  
  bool lastPulse = false;  


  for (int i = 1; i<changeCount; i=i+2) 
  {
    lastPulse = (i+1 == changeCount);

    if  (
      RCSwitch::timings[i]   > delay - delayTolerance 
      && RCSwitch::timings[i]   < delay + delayTolerance 
      && (lastPulse ||      
      (RCSwitch::timings[i+1] > delay*MC145026_LONG_CYCLES  - delayTolerance 
      && RCSwitch::timings[i+1] < delay*MC145026_LONG_CYCLES  + delayTolerance)) )     {
            
      thisValue = false;
    } 
    else if (RCSwitch::timings[i]   > delay*MC145026_LONG_CYCLES - delayTolerance
      && RCSwitch::timings[i]   < delay*MC145026_LONG_CYCLES + delayTolerance
      && (lastPulse || 
      (RCSwitch::timings[i+1] > delay  - delayTolerance
      && RCSwitch::timings[i+1] < delay  + delayTolerance))) {

      thisValue = true;
    } 
    else {
      // Failed
      return false;
    }

    if (hasPrevValue) {
      char c =  thisValue ? (prevValue ? '1' : 'E') : (prevValue ? 'F' : '0'); // E = error, 0 + 1 not a valid combo
      if (c == 'E') return false;
      code[codePos++] = c;
      hasPrevValue = false;        
    }
    else {
      hasPrevValue = true;
      prevValue = thisValue;
    }
    
  }      

 
  if (hasPrevValue) {
    return false; // half a value is left?
  }

  code[codePos] = 0; // nullterm

  RCSwitch::nReceivedCodeLen =  codePos;
  strcpy(RCSwitch::nReceivedCodeDesc, "Code [01F]: ");
  RCSwitch::nReceivedDelay = delay;
  RCSwitch::nReceivedProtocol = 5;

  return true;
}

static char getNexaCode(unsigned int shortPulses)
{
  if (shortPulses == 0)
    return '0';
  else if (shortPulses == 1)
    return '1';
  else if (shortPulses == 2)
    return '2';
  else
    return 'E'; //ERROR
}

// Nexa \ CoCo
bool RCSwitch::receiveProtocol6(unsigned int changeCount){

  if (changeCount != 132) {
    return false;
  }

  //      unsigned long delay = RCSwitch::timings[2] / 11;//9; // more reliable than using timings[1]    TROR DET ER 12 som er riktig her. med ca 224 pulse
  unsigned long delay = RCSwitch::timings[0] / 46;
  unsigned long delayTolerance = delay * RCSwitch::nReceiveTolerance * 0.01;    

  char* code = RCSwitch::nReceivedCode;
  int codePos = 0;
  int shortPulses = 0;
  bool lastPulse = false;
  
  for (int i = 3; i<changeCount/*-1*/ ; i=i+2) 
  {
    lastPulse = (i+1 == changeCount);
    
    if  (!lastPulse 
      && RCSwitch::timings[i]   > delay - delayTolerance
      && RCSwitch::timings[i]   < delay + delayTolerance
      && RCSwitch::timings[i+1] > delay  - delayTolerance
      && RCSwitch::timings[i+1] < delay  + delayTolerance) {

      shortPulses++;
    } 
    else if (RCSwitch::timings[i]   > delay - delayTolerance
      && RCSwitch::timings[i]   < delay + delayTolerance
      && (lastPulse || 
      (RCSwitch::timings[i+1] > delay * 6  - delayTolerance
      && RCSwitch::timings[i+1] < delay * 6  + delayTolerance))) {

      code[codePos++] = getNexaCode(shortPulses);
      shortPulses = 0;
    } 
    else {
      // Failed
      return false;
    }
  }      

  if (shortPulses > 0) {
    return false;
  }
  
  code[codePos] = 0; //nullterm

  strcpy(RCSwitch::nReceivedCodeDesc, "Code [012]: ");
  RCSwitch::nReceivedCodeLen = codePos;
  RCSwitch::nReceivedDelay = delay;
  RCSwitch::nReceivedProtocol = 6;

  return true;
}


void RCSwitch::handleInterrupt() {

  static unsigned int duration;
  static unsigned int changeCount;
  static unsigned long lastTime;
  static unsigned int repeatCount;


  long time = micros();
  duration = time - lastTime;

  if (duration > 5000 && duration > RCSwitch::timings[0] - 200 && duration < RCSwitch::timings[0] + 200) {
    repeatCount++;
    // changeCount--;
    if (repeatCount == 2) {

      RCSwitch::nChangeCount = changeCount;

      bool ok = receiveProtocol1(changeCount);
      if (!ok)
        ok = receiveProtocol2(changeCount);
      if (!ok)        
        ok = receiveProtocol3(changeCount);
      if (!ok)        
        ok = receiveProtocol4(changeCount);
      if (!ok)        
        ok = receiveProtocol5(changeCount);
      if (!ok)        
        ok = receiveProtocol6(changeCount);

      RCSwitch::bAvailable = ok;

      repeatCount = 0;
    }

    changeCount = 0;
  } 
  else if (duration > 5000) {
    changeCount = 0;
  }

  if (changeCount >= RCSWITCH_MAX_CHANGES) {
    changeCount = 0;
    repeatCount = 0;
  }
  RCSwitch::timings[changeCount++] = duration;
  lastTime = time;  
}
#endif









